using System;
using System.Runtime.Serialization;
using System.Security.Permissions;
using InfiniTec.Exchange.Notifications.Microsoft.Exchange.WebServices;

namespace InfiniTec.Exchange.Notifications
{
	/// <summary>
	/// Reference to a folder in an Exchange 2007 or later mailbox or public folder. This can either be a well-known folder
	/// (Public Folders root, one of the default folders) or a specific folder referenced by an Exchange 2007 folder id.
	/// </summary>
	[Serializable]
    [KnownType(typeof(WellKnownFolderId))]
	[KnownType(typeof(MailboxReference))]
	public sealed class FolderReference: ISerializable
	{
		/// <summary>
		/// Gets the mailbox this instance points to. If set to <see langword="null"/>, the mailbox of the current user is referenced.
		/// </summary>
		/// <value>The mailbox.</value>
		public MailboxReference Mailbox { get; private set; }
		/// <summary>
		/// Gets or sets the folder id.
		/// </summary>
		/// <value>The folder id.</value>
		public string FolderId { get; private set; }

		internal FolderReference(BaseFolderIdType folderId)
		{
			if (folderId == null) throw new ArgumentNullException("folderId");
			var distinguishedFolderId = folderId as DistinguishedFolderIdType;
			var folderIdType = folderId as FolderIdType;

			if (distinguishedFolderId != null)
			{
				WellKnownFolderId = (WellKnownFolderId) distinguishedFolderId.Id;
				if (distinguishedFolderId.Mailbox != null)
				{
					Mailbox = new MailboxReference(distinguishedFolderId.Mailbox);
				}
			}
			else if (folderIdType != null)
			{
				FolderId = folderIdType.Id;
			}
		}

		/// <summary>
		/// Gets or sets the well known folder id.
		/// </summary>
		/// <value>The well known folder id.</value>
		public WellKnownFolderId? WellKnownFolderId
		{
			get; private set;
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="FolderReference"/> class.
		/// </summary>
		/// <param name="wellKnownFolderId">The well known folder id.</param>
		public FolderReference(WellKnownFolderId? wellKnownFolderId)
		{
			WellKnownFolderId = wellKnownFolderId;
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="FolderReference"/> class.
		/// </summary>
		/// <param name="wellKnownFolderId">The well known folder id.</param>
		/// <param name="mailbox">The mailbox.</param>
		public FolderReference(WellKnownFolderId? wellKnownFolderId, MailboxReference mailbox)
		{
			WellKnownFolderId = wellKnownFolderId;
			Mailbox = mailbox;
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="FolderReference"/> class.
		/// </summary>
		/// <param name="folderId">The folder id.</param>
		public FolderReference(string folderId)
		{
			FolderId = folderId;
		}

		/// <summary>
		/// Converts the folder reference to a reference usable with Exchange 2007 WebServices.
		/// </summary>
		/// <returns></returns>
		internal BaseFolderIdType ToEwsFolderId()
		{
			if (WellKnownFolderId != null)
			{
				return new DistinguishedFolderIdType
				       	{
				       		Id = (DistinguishedFolderIdNameType) WellKnownFolderId,
				       		Mailbox = Mailbox != null ? Mailbox.ToEwsMailbox() : null
				       	};
			}
			return new FolderIdType
			       	{
			       		Id = FolderId
			       	};
		}

		/// <summary>
		/// Populates a <see cref="T:System.Runtime.Serialization.SerializationInfo"/> with the data needed to serialize the target object.
		/// </summary>
		/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo"/> to populate with data.</param>
		/// <param name="context">The destination (see <see cref="T:System.Runtime.Serialization.StreamingContext"/>) for this serialization.</param>
		/// <exception cref="T:System.Security.SecurityException">The caller does not have the required permission. </exception>
		[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
		void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
		{
			info.AddValue("Mailbox", Mailbox);
			info.AddValue("WellKnownFolderId", WellKnownFolderId);
			info.AddValue("FolderId", FolderId);
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="FolderReference"/> class.
		/// </summary>
		/// <param name="info">The info.</param>
		/// <param name="context">The context.</param>
		private FolderReference(SerializationInfo info, StreamingContext context)
		{
			Mailbox = (MailboxReference) info.GetValue("Mailbox", typeof (MailboxReference));
			WellKnownFolderId = (WellKnownFolderId?) info.GetValue("WellKnownFolderId", typeof (WellKnownFolderId?));
			FolderId = info.GetString("FolderId");
		}
	}
}